<?php

class ThreeSmug {

	private $useragent = 'ThreeSmug/0.2';
	private $endpoint = '1.2.2';
	private $api = "://api.smugmug.com/services/api/php/";
	private $username;
	private $password;
	private $api_key;
	private $sid;
	private $uploads = array();
	private $failed = array();
	private $albums = array();

	public $testing;
	public $delete;
	/**
	 *
	 * @var array Methods that change things
	 */
	private $changeMethods = array(
		'smugmug.albums.applyWatermark',
		'smugmug.albums.changeSettings',
		'smugmug.albums.comments.add',
		'smugmug.albums.create',
		'smugmug.albums.delete',
		'smugmug.albums.removeWatermark',
		'smugmug.albums.reSort',
		'smugmug.albumtemplates.changeSettings',
		'smugmug.albumtemplates.create',
		'smugmug.albumtemplates.delete',
		'smugmug.categories.create',
		'smugmug.categories.delete',
		'smugmug.categories.rename',
		'smugmug.coupons.create',
		'smugmug.coupons.modify',
		'smugmug.family.add',
		'smugmug.family.remove',
		'smugmug.family.removeAll',
		'smugmug.friends.add',
		'smugmug.friends.remove',
		'smugmug.friends.removeAll',
		'smugmug.images.applyWatermark',
		'smugmug.images.changePosition',
		'smugmug.images.changeSettings',
		'smugmug.images.crop',
		'smugmug.images.delete',
		'smugmug.images.removeWatermark',
		'smugmug.images.rotate',
		'smugmug.images.upload',
		'smugmug.images.uploadFromURL',
		'smugmug.printmarks.create',
		'smugmug.printmarks.delete',
		'smugmug.printmarks.modify',
		'smugmug.sharegroups.albums.add',
		'smugmug.sharegroups.albums.remove',
		'smugmug.sharegroups.create',
		'smugmug.sharegroups.delete',
		'smugmug.sharegroups.modify',
		'smugmug.subcategories.create',
		'smugmug.subcategories.delete',
		'smugmug.subcategories.rename',
		'smugmug.watermarks.changeSettings',
		'smugmug.watermarks.create',
		'smugmug.watermarks.delete',
	);
	/**
	 * For batch curl processes
	 * @var object RollingCurl
	 */
	private $rc;
	/**
	 * For single requests
	 * @var object RollingCurl
	 */
	private $sc;

	/**
	 * @return void
	 */
	public function __construct() {
		$config = parse_ini_file('config.ini', true);
		
		foreach ($config as $section => $value) {
			foreach ($value as $key => $setting) {
				if ($section == 'settings') {
					$this->$key = $setting;
				} else {
					$this->albums[$section][$key] = $setting;
				}
			}
		}

		require_once('class.rollingcurl.php');
		$this->rc = new RollingCurl(array($this, 'rcCallback'));
		$this->rc->options = array(CURLOPT_USERAGENT => $this->useragent);
		$this->rc->window_size = 5;

		$this->sc = new RollingCurl();
		$this->sc->options = array(
			CURLOPT_USERAGENT => $this->useragent,
		);

		// Login to get the session id
		$result = $this->login_withPassword(
						"APIKey={$this->api_key}",
						"EmailAddress={$this->username}",
						"Password={$this->password}"
		);

		if ($result) {
			$this->sid = $result['Session']['id'];
		}
	}

	/**
	 * Generic caller function. Will run most API calls based on name
	 *
	 * @param string $name
	 * @param mixed $arguments Associative array or Strings following "Name=Value"
	 * @throws Exception
	 * @return mixed
	 */
	public function __call($name, $arguments) {
		$method = 'smugmug.' . str_replace('_', '.', $name);

		// If we're just testing, don't do anything that will change stuff
		if ($this->testing && in_array($method, $this->changeMethods)) {
			return;
		}

		// Args parsing stolen from phpSmug
		$args = $this->parseArgs($arguments);

		$args['method'] = $method;

		if (!empty($this->sid)) {
			$args['SessionID'] = $this->sid;
		}

		ksort($args);

		// https for login calls
		if (strpos($name, 'login_') !== false) {
			$proto = 'https';
		} else {
			$proto = 'http';
		}
		$url = $proto . $this->api . $this->endpoint . '/';

		$this->sc->post($url, $args);
		$result = $this->sc->execute();
		$result = unserialize($result);

		if ($result['stat'] == 'ok') {
			foreach ($result as $r) {
				if (is_array($r)) {
					return $r;
				}
			}

			return true;
		} else {
			throw new Exception($result['message'], $result['code']);
		}
	}

	public function images_upload() {
		$args = $this->parseArgs(func_get_args());
		$args['method'] = 'smugmug.images.upload';

		// Set FileName, if one isn't provided in the method call
		if (!array_key_exists('FileName', $args)) {
			$args['FileName'] = basename($args['File']);
		}

		$url = 'http://upload.smugmug.com/' . urlencode(basename($args['FileName']));
		$request = new Request($url);

		// Header handling mostly stolen from phpSmug
		$headers[] = 'Expect:';
		$headers[] = 'User-Agent: ' . $this->useragent;
		$headers[] = 'Content-MD5: ' . md5_file($args['File']);
		$headers[] = 'X-Smug-Version: ' . $this->endpoint;
		$headers[] = 'X-Smug-SessionID: ' . $this->sid;
		$headers[] = 'X-Smug-ResponseType: ' . 'PHP';
		$headers[] = 'X-Smug-AlbumID: ' . $args['AlbumID'];
		$headers[] = 'X-Smug-Filename: ' . $args['FileName'];

		(isset($args['ImageID'])) ? $headers[] = 'X-Smug-ImageID: ' . $args['ImageID'] : false;
		(isset($args['Caption'])) ? $headers[] = 'X-Smug-Caption: ' . $args['Caption'] : false;
		(isset($args['Keywords'])) ? $headers[] = 'X-Smug-Keywords: ' . $args['Keywords'] : false;
		(isset($args['Latitude'])) ? $headers[] = 'X-Smug-Latitude: ' . $args['Latitude'] : false;
		(isset($args['Longitude'])) ? $headers[] = 'X-Smug-Longitude: ' . $args['Longitude'] : false;
		(isset($args['Altitude'])) ? $headers[] = 'X-Smug-Altitude: ' . $args['Altitude'] : false;

		$request->options = array(
			CURLOPT_PUT => true,
			CURLOPT_INFILE => fopen($args['File'], 'r'),
			CURLOPT_INFILESIZE => filesize($args['File']),
			CURLOPT_HTTPHEADER => $headers,
		);
		$this->rc->add($request);
		$this->uploads[$url] = $args['FileName'];
	}

	public function batchUpload() {
		if (!empty($this->uploads) && !$this->testing) {
			$this->rc->execute();
			$this->rc->requests = array();
		}

		return true;
	}

	public function rcCallback($output, $info) {
		$result = unserialize($output);
		if ($result) {
			$output = $result;
			$msg = '.';
			if ($output['stat'] != 'ok') {
				$msg = 'X';
				$this->failed[] = array(
					'file' => $this->uploads[$info['url']],
					'message' => $output
				);
			}
		} else if ($info['http_code'] > 399) {

			$msg = 'X';
			$this->failed[] = array(
				'file' => $this->uploads[$info['url']],
				'message' => 'HTTP Error - Probably timeout'
			);
		}

		if ($info['http_code'] == 100) {
			$this->failed[] = array(
				'file' => $this->uploads[$info['url']],
				'message' => 'HTTP 100 - You can probably try this again'
			);
		}
		unset($this->uploads[$info['url']]);

		echo $msg;
	}

	public function getFailed() {
		return $this->failed;
	}

	public function deleteAllowed($album) {
		if(isset($this->albums[$album])){
			if(isset($this->albums[$album]['delete'])) {
				return $this->albums[$album]['delete'];
			}
		}

		return $this->delete;
	}

	private function parseArgs($arguments) {
		$args = array();
		if (!empty($arguments)) {
			foreach ($arguments as $arg) {
				if (is_array($arg)) {
					$args = array_merge($args, $arg);
				} else {
					$exp = explode('=', $arg, 2);
					$args[$exp[0]] = $exp[1];
				}
			}
		}

		return $args;
	}

}